/*
 * Copyright 2025 The JA-SIG Collaborative. All rights reserved.
 * distributed with this file and available online at
 */
package com.lap.auth.adapter.driving.persistence.region.repository;

import com.lap.auth.adapter.driving.persistence.region.RegionConverter;
import com.lap.auth.adapter.driving.persistence.region.mapper.RegionMapper;
import com.lap.auth.adapter.driving.persistence.region.po.RegionPo;
import com.lap.auth.domain.region.Region;
import com.lap.auth.domain.region.repository.RegionRepository;
import com.lap.auth.shared.tools.PersistenceUtil;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.stereotype.Repository;

@RequiredArgsConstructor
@Repository
public class RegionRepositoryImpl implements RegionRepository {

  private final SqlSessionFactory sqlSessionFactory;
  private final RegionConverter regionConverter;
  private final RegionMapper regionMapper;

  @Override
  public Integer save(Region region) {
    RegionPo regionPo = regionConverter.toPo(region);
    if (region.isNew()) {
      regionMapper.insert(regionPo);
      return regionPo.getId();
    }
    return regionMapper.updateByPrimaryKey(regionPo);
  }

  @Override
  public void saveAll(Region region, List<Region> children) {
    RegionPo regionPo = regionConverter.toPo(region);
    if (region.isNew()) {
      regionMapper.insert(regionPo);
    } else {
      regionMapper.updateByPrimaryKey(regionPo);
    }

    List<RegionPo> dataList = regionConverter.toPoList(regionPo.getId(), children);
    PersistenceUtil.syncChildrenByParent(
        regionPo.getId(),
        dataList,
        RegionPo::getId,
        regionMapper::selectByPid,
        regionMapper::insertBatch,
        this::updateBatch,
        regionMapper::deleteByIds);
  }

  private void updateBatch(List<RegionPo> regionPos) {
    try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) {
      RegionMapper mapper = sqlSession.getMapper(RegionMapper.class);
      for (RegionPo item : regionPos) {
        mapper.updateByPrimaryKey(item);
      }
      sqlSession.flushStatements();
    }
  }

  @Override
  public List<Region> findByPid(Integer parentId) {
    List<RegionPo> allList = regionMapper.selectByPid(parentId);
    return regionConverter.toDomains(allList);
  }

  @Override
  public List<Region> findByIds(Set<Integer> idSet) {
    if (CollectionUtils.isEmpty(idSet)) {
      return Collections.emptyList();
    }
    List<RegionPo> all = regionMapper.selectByIds(idSet.stream().toList());
    return regionConverter.toDomains(all);
  }

  @Override
  public List<Region> findAll() {
    List<RegionPo> all = regionMapper.selectAll();
    return regionConverter.toDomains(all);
  }

  @Override
  public Optional<Region> findById(Integer id) {
    var regionDO = regionMapper.selectByPrimaryKey(id);
    return Optional.ofNullable(regionConverter.toDomain(regionDO));
  }

  @Override
  public int deleteById(Integer id) {
    return regionMapper.deleteByPrimaryKey(id);
  }
}
